import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.List;

import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

import me.w70.bot.Bot;
import me.w70.bot.scripting.Random;
import me.w70.bot.scripting.Script;
import me.w70.bot.util.DebugInterfacesUI;
import me.w70.bot.wrappers.RSInterface;
import me.w70.bot.wrappers.RSInterfaceGroup;
import me.w70.hooks.Interface;


public class DebugInterfaces extends Script implements TreeSelectionListener {


	@Override
	public String getScriptAuthor() {
		return "spooky";
	}

	@Override
	public String getScriptCategory() {
		return "Debug_II";
	}

	@Override
	public String getScriptDescription() {
		return "Interface Debug";
	}

	@Override
	public String getScriptName() {
		return "Interface Debug";
	}

	 private DebugInterfacesUI UI;

	    public boolean active() {
	        return UI.isVisible();
	    }




	    @Override
	    public boolean onLoad() {
	        UI = new DebugInterfacesUI();
	        UI.interfaceTree.addTreeSelectionListener(this);
	        UI.updateButton.addActionListener(new ActionListener() {
	            public void actionPerformed(ActionEvent e) {
	                updateTree();
	            }
	        });

	        UI.searchTextButton.addActionListener(new ActionListener() {
	            public void actionPerformed(ActionEvent e) {
	                UI.filterByTextFrame.setVisible(false);
	                updateTree(UI.searchTextField.getText());
	            }
	        });
	        updateTree();
	        UI.setVisible(true);
	        return true;
	    }

	    public void updateTree() {
	    	try {
	        DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Root");
	        List<RSInterfaceGroup> loadedInterfaces = new LinkedList<RSInterfaceGroup>();
	        Interface[][] interfaces = getClient().getInterfaces();
	        for (int i = 0; i < interfaces.length; i++) {
	            if (interfaces[i] == null)
	                continue;
	            loadedInterfaces.add(new RSInterfaceGroup(interfaces[i], i));
	        }
	        fillTree(rootNode, loadedInterfaces);
	    	}catch(Exception e) {
	    		
	    	}
	    }

	    public void updateTree(String textSearch) {
	        DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Root");
	        List<RSInterfaceGroup> loadedInterfaces = new LinkedList<RSInterfaceGroup>();
	        Interface[][] interfaces = getClient().getInterfaces();
	        for (int i = 0; i < interfaces.length; i++) {
	            if (interfaces[i] == null)
	                continue;
	            RSInterfaceGroup group = new RSInterfaceGroup(interfaces[i], i);
	            RSInterface[] children = group.getChildren();
	            for (int a = 0; a < children.length; a++) {
	              RSInterface face = children[a];
	                face.setIndex(a);
	                if (searchInterfaceForText(face, textSearch)) {
	                    loadedInterfaces.add(group);
	                    break;
	                }
	            }
	        }
	        fillTree(rootNode, loadedInterfaces);
	    }

	    public boolean searchInterfaceForText(RSInterface face, String searchText) {
	        if (face == null || !face.isValid())
	            return false;
	        if (face.textContainsIgnoreCase(searchText)) {
	            Bot.addMessage(this, "Found in " + face.toString() + (face.hasParrent() ? " at " + face.getParrent().toString() : ""));
	            return true;
	        }
	        RSInterface[] children = face.getChildren();
	        if (children == null || children.length == 0)
	            return false;
	        for (int i = 0; i < children.length; i++) {
	            RSInterface child = children[i];
	            child.setIndex(i);
	            if (searchInterfaceForText(child, searchText)) {
	                return true;
	            }
	        }
	        return false;
	    }

	    private void fillTree(DefaultMutableTreeNode rootNode, List<RSInterfaceGroup> loadedInterfaces) {
	        for (RSInterfaceGroup group : loadedInterfaces) {
	            DefaultMutableTreeNode groupNode = new DefaultMutableTreeNode(group);
	            RSInterface[] children = group.getChildren();
	            for (int i = 0; i < children.length; i++) {
	                if (children[i] == null || !children[i].isValid()) {
	                    continue;
	                }
	                children[i].setIndex(i);
	                DefaultMutableTreeNode interfaceNode = new DefaultMutableTreeNode(children[i]);
	                fillNode(interfaceNode, children[i]);
	                groupNode.add(interfaceNode);
	            }
	            rootNode.add(groupNode);
	        }
	        UI.interfaceTree.setModel(new DefaultTreeModel(rootNode));
	        UI.interfaceTree.updateUI();
	    }

	    public void fillNode(DefaultMutableTreeNode node, RSInterface face) {
	        if(face == null)
	            return;
	        RSInterface[] children = face.getChildren();
	        if (children == null || children.length == 0)
	            return;
	        for (int i = 0; i < children.length; i++) {
	            if(children[i] == null){
	                continue;
	            }
	            children[i].setIndex(i);
	            DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(children[i]);
	            fillNode(childNode, children[i]);
	            node.add(childNode);
	        }
	    }

	    public int loop() {
	        return 1000;
	    }



	    public void draw(Graphics g) {
	        DefaultMutableTreeNode node = (DefaultMutableTreeNode) UI.interfaceTree.getLastSelectedPathComponent();
	        if (node == null){
	            UI.infoTable.setModel(new DefaultTableModel(
	                    new Object[][]{
	                            {"The selected interface was null."},
	                            {"Can not recieve any information from it."}
	                    },
	                    new String[]{
	                            "Interface information"
	                    }
	            ) {
	                Class[] columnTypes = new Class[]{
	                        String.class
	                };
	                boolean[] columnEditable = new boolean[]{
	                        false
	                };

	                @Override
	                public Class<?> getColumnClass(int columnIndex) {
	                    return columnTypes[columnIndex];
	                }

	                @Override
	                public boolean isCellEditable(int rowIndex, int columnIndex) {
	                    return columnEditable[columnIndex];
	                }
	            });
	            return;
	        }
	        Object nodeInfo = node.getUserObject();
	        if (nodeInfo instanceof RSInterface) {
	            g.setColor(Color.orange);
	            Rectangle rect = ((RSInterface) nodeInfo).getArea();
	            g.drawRect(rect.x, rect.y, rect.width, rect.height);
	        }
	    }

	    public void valueChanged(TreeSelectionEvent e) {
	        DefaultMutableTreeNode node = (DefaultMutableTreeNode) UI.interfaceTree.getLastSelectedPathComponent();
	        if (node == null){
	            return;
	        }
	        Object nodeInfo = node.getUserObject();
	        if (nodeInfo instanceof RSInterface) {
	            RSInterface face = (RSInterface) nodeInfo;

	            List<Object[]> data = new LinkedList<Object[]>();
	            data.add(new Object[]{"Screen position:"});
	            Rectangle rect = face.getArea();
	            data.add(new Object[]{"    x: " + rect.getX()});
	            data.add(new Object[]{"    y: " + rect.getY()});
	            data.add(new Object[]{"    width: " + rect.getWidth()});
	            data.add(new Object[]{"    height: " + rect.getHeight()});
	            data.add(new Object[]{""});
	            data.add(new Object[]{"Relative position"});
	            data.add(new Object[]{"    x: " + face.getX()});
	            data.add(new Object[]{"    y: " + face.getY()});
	            data.add(new Object[]{""});
	            data.add(new Object[]{"Text:"});
	            data.add(new Object[]{"    Text: " + face.getText()});
	            data.add(new Object[]{"    Text color: " + face.getTextColor()});
	            data.add(new Object[]{"    Texture ID: " + face.getTextureID()});
	            data.add(new Object[]{""});
	            data.add(new Object[]{"Model ID: " +face.getModelID()});
	            data.add(new Object[]{"Model Type: " +face.getModelType()});
	            data.add(new Object[]{""});
	            String[] actions = face.getActions();
	            if (actions != null) {
	                data.add(new Object[]{"Actions :"});
	                for (String action : actions) {
	                    data.add(new Object[]{"        " + action});
	                }
	            }
	            data.add(new Object[]{""});
	            data.add(new Object[]{"Contained item"});
	            data.add(new Object[]{"    ID: " + face.getContainedItemID()});
	            data.add(new Object[]{"    Name: " + face.getContainedItemName()});
	            data.add(new Object[]{"    Stack size: " + face.getContainedItemStackSize()});
	            data.add(new Object[]{""});
	            int[] inventory = face.getItemIDArray();
	            if (inventory != null) {
	                String out = "Item ID Array: {";
	                for (int id : inventory) {
	                    out += id + ", ";
	                }
	                out += "}";
	                data.add(new Object[]{out});
	            }
	            data.add(new Object[]{""});
	            int[] stackSizes = face.getItemStackSizeArray();
	            if (stackSizes != null) {
	                String out = "Item Stack Size Array: {";
	                for (int stackSize : stackSizes) {
	                    out += stackSize + ", ";
	                }
	                out += "}";
	                data.add(new Object[]{out});
	            }

	            UI.infoTable.setModel(new DefaultTableModel(
	                    data.toArray(new Object[1][1]),
	                    new String[]{
	                            "Interface information"
	                    }
	            ) {
	                Class[] columnTypes = new Class[]{
	                        String.class
	                };
	                boolean[] columnEditable = new boolean[]{
	                        false
	                };

	                @Override
	                public Class<?> getColumnClass(int columnIndex) {
	                    return columnTypes[columnIndex];
	                }

	                @Override
	                public boolean isCellEditable(int rowIndex, int columnIndex) {
	                    return columnEditable[columnIndex];
	                }
	            });

	        } else {
	            UI.infoTable.setModel(new DefaultTableModel(
	                    new Object[][]{
	                            {"Select an interface."},
	                    },
	                    new String[]{
	                            "Interface information"
	                    }
	            ) {
	                Class[] columnTypes = new Class[]{
	                        String.class
	                };
	                boolean[] columnEditable = new boolean[]{
	                        false
	                };

	                @Override
	                public Class<?> getColumnClass(int columnIndex) {
	                    return columnTypes[columnIndex];
	                }

	                @Override
	                public boolean isCellEditable(int rowIndex, int columnIndex) {
	                    return columnEditable[columnIndex];
	                }
	            });
	        }
	    }

	    /**
	     * Used to make random counters or/and cancel randoms.
	     *
	     * @param random an instance of the random.
	     *               You may use the methods to get name and description.
	     *               And you can cast it to get internal methods for the random.
	     * @return if the random shall run or not.
	     *         Leaving this to false without handling the random yourself may be dangerous!
	     */
	    public boolean onRandomActivate(Random random) {
	        return false;  // Its a debug script.
	    }

	
	

}
